package com.xtpt.disaster.controller;

import com.alibaba.fastjson.JSON;
import com.xtpt.disaster.bean.ActionParameters;
import com.xtpt.disaster.bean.ClientCmdExecResult;
import com.xtpt.disaster.bean.JobDetail;
import com.xtpt.disaster.bean.TaskInfo;
import com.xtpt.disaster.common.PortalResult;
import com.xtpt.disaster.common.PropertyConfig;
import com.xtpt.disaster.common.consts.DataTypeEnum;
import com.xtpt.disaster.common.consts.DbBackupTypeEnum;
import com.xtpt.disaster.common.consts.StatusConst;
import com.xtpt.disaster.common.consts.TaskTypeEnum;
import com.xtpt.disaster.service.*;
import com.xtpt.disaster.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.nio.file.Paths;

/**
 * @author jack_xin
 * @ClassName FileActionController
 * @Desc 使用java代理进行文件备份恢复
 * @date 2021年12月24日 14:18
 * @Version TODO
 */
@RestController
@RequestMapping(value = "/file")
public class    FileActionController {
    @Autowired
    TaskInfoManageService taskInfoManageService;

    @Autowired
    NodeInfoManageService nodeInfoManageService;

    @Autowired
    PropertyConfig config;

    @Autowired
    ActionParameters actionParameters;

    @Autowired
    QuartzSendBack quartzSendBack;

    @Autowired
    FileBackupService fileBackupService;

    @Autowired
    FileRecoverService fileRecoverService;

    @Autowired
    ParseFileAbsolutePath fileAbsolutePath;

    @Autowired
    JobDetailService jobDetailService;

    /**
     * @Author jack xin
     * @Method Name submitTask
     * @Desc 文件备份恢复任务的提交接口，提交任务记录，并将备份或者恢复接口地址以及参数taskInfo提交给定时调度接口，实现定时。
     * @Param [taskInfo]
     * @return com.xtpt.disaster.common.PortalResult
     * @Date 9:14 2021/12/28
     **/
    @PostMapping(value = "/submit")
    public PortalResult submitTask(@RequestBody TaskInfo taskInfo) {
        try{
            Long taskId = IDGenerator.longid();
            taskInfo.setTaskId(taskId);
            PortalResult result = taskInfoManageService.insertTaskInfo(taskInfo);
            Integer dataType = taskInfo.getTaskFileType();

            if ( StatusConst.ERROR.equals(result.getStatus()) ) return result;
            if ( (!dataType.equals(DataTypeEnum.FILE.getValue())) && (!dataType.equals(DataTypeEnum.VIRTUAL.getValue())) ) return PortalResult.error("数据类型错误，请选择文件或镜像进行备份！");

            Integer taskType = taskInfo.getTaskType();
            Integer taskBackupType = taskInfo.getTaskBackupType();
            String taskUrl = "http://" + config.getServerIp() + ":" + config.getServerPort();
            actionParameters.setRequestMethod("POST");
            if (taskType.equals(TaskTypeEnum.RECOVER.getValue())) {
                taskUrl += "/file/recover";
                actionParameters.setRequestUrl(taskUrl);
                actionParameters.setRequestParameters(taskInfo);
                return quartzSendBack.sqlServerTaskCallBack(taskInfo, actionParameters);
            }
            else if (taskType.equals(TaskTypeEnum.BACKUP.getValue())) {
                if (taskBackupType.equals(DbBackupTypeEnum.INCREMENT.getValue())) {
                    taskUrl += "/file/increbackup";
                }
                else taskUrl += "/file/backup";
                actionParameters.setRequestUrl(taskUrl);
                actionParameters.setRequestParameters(taskInfo);
                return quartzSendBack.sqlServerTaskCallBack(taskInfo, actionParameters);
            }
            else return PortalResult.error("任务类型错误！");
        } catch (Exception e) {
            return PortalResult.error(e.getMessage());
        }
    }

    /**
     * @Author jack xin
     * @Method Name fileBackup
     * @Desc 文件备份接口，使用代理实现文件的即时、定时周期的全量备份，目前不支持增量备份。
     * @Param [taskInfo]
     * @return com.xtpt.disaster.common.PortalResult
     * @Date 9:16 2021/12/28
     **/
    @PostMapping(value = "/backup")
    public PortalResult fileBackup(@RequestBody TaskInfo taskInfo) {
        try {
            String clientPath = taskInfo.getTaskClientPath();
            Long nodeId = taskInfo.getNodeId();
            String fileName = fileAbsolutePath.parseFilePath(clientPath, nodeId);
            return fileBackupService.FileBackupByAgent(taskInfo, fileName);
        }
        catch (Exception e) {
            return PortalResult.error(e.getMessage());
        }
    }


    /*
     * @Author jack xin
     * @Method Name fileIncrementBackup
     * @Desc 文件增量备份服务接口
     * @Param [taskInfo]
     * @return com.xtpt.disaster.common.PortalResult
     * @Date 10:55 2022/4/7
     **/
    @PostMapping(value = "/increbackup")
    public PortalResult fileIncrementBackup(@RequestBody TaskInfo taskInfo) {
        try {
            String clientPath = taskInfo.getTaskClientPath();
            Long nodeId = taskInfo.getNodeId();
            String fileName = fileAbsolutePath.parseFilePath(clientPath, nodeId);
            return fileBackupService.FileIncrementBackupByRsync(taskInfo, fileName);
        }
        catch (Exception e) {
            return PortalResult.error(e.getMessage());
        }
    }

    /**
     * @Author jack xin
     * @Method Name fileRecover
     * @Desc 文件恢复接口，使用代理实现文件的即时、定时周期的恢复。
     * @Param [taskInfo]
     * @return com.xtpt.disaster.common.PortalResult
     * @Date 9:17 2021/12/28
     **/
    @PostMapping(value = "/recover")
    public PortalResult fileRecover(@RequestBody TaskInfo taskInfo) {
        return fileRecoverService.fileRecoverByAgent(taskInfo);
    }

    /**
     * @Description: 接收代理客户端任务执行结果
     * @Author: hpc
     * @Date: 2021/12/27 下午 3:13
     * @param jobId: 结果所属作业ID
     * @param resultStr: 结果字符串本身
     * @return: com.xtpt.disaster.common.PortalResult
     **/
    @RequestMapping("/receiver/{jobId}")
    public PortalResult receiver(@PathVariable("jobId") Long jobId, @RequestBody String resultStr)
    {
        if(jobId!=null && !StringUtils.isEmpty(resultStr))
        {
            JobDetail jobDetail=jobDetailService.getById(jobId);
            if(jobDetail==null)
            {
                LogUtil.logger.error("jobId:"+jobId+" 不存在！");
                return PortalResult.error(jobId+" 不存在！");
            }
            try {
                ClientCmdExecResult result= JSON.parseObject(resultStr,ClientCmdExecResult.class);
                jobDetail.setJobResult(JSON.toJSONString(result.getExecCmdResult()));
                jobDetail.setJobEndTime(TimeUtil.dateMaker());
                if(!result.isStatus())
                {
                    LogUtil.logger.error(JSON.toJSONString(result.getErrorCmdList()));
                }
                String serverFilesPath = jobDetail.getServerPath();
                boolean transOK=true;
                if(serverFilesPath!=null)
                {
                    for (String file:serverFilesPath.split(",")) {
                        transOK=cn.hutool.core.io.file.PathUtil.exists(Paths.get(file),true);
                        if(!transOK)
                        {
                            LogUtil.logger.error("文件："+file+"，未传输到服务器！");
                            break;
                        }
                    }
                }
                if(transOK)
                {
                    jobDetail.setJobStatus(StatusConst.SUCCESS);
                }
                else
                {
                    jobDetail.setJobStatus(StatusConst.ERROR);
                }
            }
            catch (Exception ex){
                jobDetail.setJobStatus(StatusConst.ERROR);
                jobDetail.setJobResult(jobDetail.getJobResult()+"\r\nException:"+ex.getMessage());
                LogUtil.logger.error(ex.getMessage());
                ex.printStackTrace();
            }
            Integer update= jobDetailService.updateByPrimaryKeySelective(jobDetail);
            LogUtil.logger.info("更新"+update+"条数据记录！");
            if(jobDetail.getJobStatus().equals(StatusConst.SUCCESS))
            {
                return PortalResult.ok("成功更新"+update+"条数据记录！");
            }
            else if(jobDetail.getJobStatus().equals(StatusConst.ERROR))
            {
                return PortalResult.ok("失败！"+jobDetail.getJobResult());
            }else
            {
                return PortalResult.ok("RUNNING");
            }
        }
        LogUtil.logger.error("结果上报参数不完整！\njobId:"+jobId+"\nresult:"+resultStr);
        return PortalResult.error("结果上报参数不完整！");
    }
}
